home *** CD-ROM | disk | FTP | other *** search
/ Amiga Plus 2000 #5 / Amiga Plus CD - 2000 - No. 5.iso / Tools / Dev / lame_src / VbrTag.c < prev    next >
Encoding:
C/C++ Source or Header  |  2000-01-01  |  12.2 KB  |  486 lines

  1. /*
  2.  *    Xing VBR tagging for LAME.
  3.  *
  4.  *    Copyright (c) 1999 A.L. Faber
  5.  *
  6.  * This library is free software; you can redistribute it and/or
  7.  * modify it under the terms of the GNU Library General Public
  8.  * License as published by the Free Software Foundation; either
  9.  * version 2 of the License, or (at your option) any later version.
  10.  *
  11.  * This library is distributed in the hope that it will be useful,
  12.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.     See the GNU
  14.  * Library General Public License for more details.
  15.  *
  16.  * You should have received a copy of the GNU Library General Public
  17.  * License along with this library; if not, write to the
  18.  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
  19.  * Boston, MA 02111-1307, USA.
  20.  */
  21.  
  22. #include "machine.h"
  23. #if defined(__riscos__) && defined(FPA10)
  24. #include    "ymath.h"
  25. #else
  26. #include    <math.h>
  27. #endif
  28. #include "VbrTag.h"
  29. #include "version.h"
  30. #include "bitstream.h"
  31.  
  32. #ifdef _DEBUG
  33. /*  #define DEBUG_VBRTAG */
  34. #endif
  35.  
  36.  
  37. const static char    VBRTag[]={"Xing"};
  38. const int SizeOfEmptyFrame[2][2]=
  39. {
  40.     {17,9},
  41.     {32,17},
  42. };
  43.  
  44.  
  45.  
  46. /****************************************************************************
  47.  * AddVbrFrame: Add VBR entry, used to fill the VBR the TOC entries
  48.  * Paramters:
  49.  *    nStreamPos: how many bytes did we write to the bitstream so far
  50.  *                (in Bytes NOT Bits)
  51.  ****************************************************************************
  52. */
  53. void AddVbrFrame(lame_global_flags *gfp)
  54. {
  55.   int nStreamPos;
  56.   lame_internal_flags *gfc=gfp->internal_flags;
  57.   nStreamPos = (gfc->bs.totbit/8);
  58.  
  59.         /* Simple exponential growing buffer */
  60.     if (gfp->pVbrFrames==NULL || gfp->nVbrFrameBufferSize==0)
  61.     {
  62.                 /* Start with 100 frames */
  63.         gfp->nVbrFrameBufferSize=100;
  64.  
  65.         /* Allocate them */
  66.         gfp->pVbrFrames=(int*)malloc((size_t)(gfp->nVbrFrameBufferSize*sizeof(int)));
  67.     }
  68.  
  69.     /* Is buffer big enough to store this new frame */
  70.     if (gfp->nVbrNumFrames==gfp->nVbrFrameBufferSize)
  71.     {
  72.                 /* Guess not, double th e buffer size */
  73.         gfp->nVbrFrameBufferSize*=2;
  74.  
  75.         /* Allocate new buffer */
  76.         gfp->pVbrFrames=(int*)realloc(gfp->pVbrFrames,(size_t)(gfp->nVbrFrameBufferSize*sizeof(int)));
  77.     }
  78.  
  79.     /* Store values */
  80.     gfp->pVbrFrames[gfp->nVbrNumFrames++]=nStreamPos;
  81. }
  82.  
  83.  
  84. /*-------------------------------------------------------------*/
  85. static int ExtractI4(unsigned char *buf)
  86. {
  87.     int x;
  88.     /* big endian extract */
  89.     x = buf[0];
  90.     x <<= 8;
  91.     x |= buf[1];
  92.     x <<= 8;
  93.     x |= buf[2];
  94.     x <<= 8;
  95.     x |= buf[3];
  96.     return x;
  97. }
  98.  
  99. void CreateI4(unsigned char *buf, int nValue)
  100. {
  101.         /* big endian create */
  102.     buf[0]=(nValue>>24)&0xff;
  103.     buf[1]=(nValue>>16)&0xff;
  104.     buf[2]=(nValue>> 8)&0xff;
  105.     buf[3]=(nValue    )&0xff;
  106. }
  107.  
  108.  
  109. /*-------------------------------------------------------------*/
  110. /* Same as GetVbrTag below, but only checks for the Xing tag.
  111.    requires buf to contain only 40 bytes */
  112. /*-------------------------------------------------------------*/
  113. int CheckVbrTag(unsigned char *buf)
  114. {
  115.     int            h_id, h_mode, h_sr_index;
  116.  
  117.     /* get selected MPEG header data */
  118.     h_id       = (buf[1] >> 3) & 1;
  119.     h_sr_index = (buf[2] >> 2) & 3;
  120.     h_mode     = (buf[3] >> 6) & 3;
  121.  
  122.     /*  determine offset of header */
  123.     if( h_id )
  124.     {
  125.                 /* mpeg1 */
  126.         if( h_mode != 3 )    buf+=(32+4);
  127.         else                buf+=(17+4);
  128.     }
  129.     else
  130.     {
  131.                 /* mpeg2 */
  132.         if( h_mode != 3 ) buf+=(17+4);
  133.         else              buf+=(9+4);
  134.     }
  135.  
  136.     if( buf[0] != VBRTag[0] ) return 0;    /* fail */
  137.     if( buf[1] != VBRTag[1] ) return 0;    /* header not found*/
  138.     if( buf[2] != VBRTag[2] ) return 0;
  139.     if( buf[3] != VBRTag[3] ) return 0;
  140.     return 1;
  141. }
  142.  
  143. int GetVbrTag(VBRTAGDATA *pTagData,  unsigned char *buf)
  144. {
  145.     int            i, head_flags;
  146.     int            h_id, h_mode, h_sr_index;
  147.     static int    sr_table[4] = { 44100, 48000, 32000, 99999 };
  148.  
  149.     /* get Vbr header data */
  150.     pTagData->flags = 0;
  151.  
  152.     /* get selected MPEG header data */
  153.     h_id       = (buf[1] >> 3) & 1;
  154.     h_sr_index = (buf[2] >> 2) & 3;
  155.     h_mode     = (buf[3] >> 6) & 3;
  156.  
  157.     /*  determine offset of header */
  158.     if( h_id )
  159.     {
  160.                 /* mpeg1 */
  161.         if( h_mode != 3 )    buf+=(32+4);
  162.         else                buf+=(17+4);
  163.     }
  164.     else
  165.     {
  166.                 /* mpeg2 */
  167.         if( h_mode != 3 ) buf+=(17+4);
  168.         else              buf+=(9+4);
  169.     }
  170.  
  171.     if( buf[0] != VBRTag[0] ) return 0;    /* fail */
  172.     if( buf[1] != VBRTag[1] ) return 0;    /* header not found*/
  173.     if( buf[2] != VBRTag[2] ) return 0;
  174.     if( buf[3] != VBRTag[3] ) return 0;
  175.  
  176.     buf+=4;
  177.  
  178.     pTagData->h_id = h_id;
  179.  
  180.     pTagData->samprate = sr_table[h_sr_index];
  181.  
  182.     if( h_id == 0 )
  183.         pTagData->samprate >>= 1;
  184.  
  185.     head_flags = pTagData->flags = ExtractI4(buf); buf+=4;      /* get flags */
  186.  
  187.     if( head_flags & FRAMES_FLAG )
  188.     {
  189.         pTagData->frames   = ExtractI4(buf); buf+=4;
  190.     }
  191.  
  192.     if( head_flags & BYTES_FLAG )
  193.     {
  194.         pTagData->bytes = ExtractI4(buf); buf+=4;
  195.     }
  196.  
  197.     if( head_flags & TOC_FLAG )
  198.     {
  199.         if( pTagData->toc != NULL )
  200.         {
  201.             for(i=0;i<NUMTOCENTRIES;i++)
  202.                 pTagData->toc[i] = buf[i];
  203.         }
  204.         buf+=NUMTOCENTRIES;
  205.     }
  206.  
  207.     pTagData->vbr_scale = -1;
  208.  
  209.     if( head_flags & VBR_SCALE_FLAG )
  210.     {
  211.         pTagData->vbr_scale = ExtractI4(buf); buf+=4;
  212.     }
  213.  
  214. #ifdef DEBUG_VBRTAG
  215.     DEBUGF("\n\n********************* VBR TAG INFO *****************\n");
  216.     DEBUGF("tag         :%s\n",VBRTag);
  217.     DEBUGF("head_flags  :%d\n",head_flags);
  218.     DEBUGF("bytes       :%d\n",pTagData->bytes);
  219.     DEBUGF("frames      :%d\n",pTagData->frames);
  220.     DEBUGF("VBR Scale   :%d\n",pTagData->vbr_scale);
  221.     DEBUGF("toc:\n");
  222.     if( pTagData->toc != NULL )
  223.     {
  224.         for(i=0;i<NUMTOCENTRIES;i++)
  225.         {
  226.             if( (i%10) == 0 ) DEBUGF("\n");
  227.             DEBUGF(" %3d", (int)(pTagData->toc[i]));
  228.         }
  229.     }
  230.     DEBUGF("\n***************** END OF VBR TAG INFO ***************\n");
  231. #endif
  232.     return 1;       /* success */
  233. }
  234.  
  235.  
  236. /****************************************************************************
  237.  * InitVbrTag: Initializes the header, and write empty frame to stream
  238.  * Paramters:
  239.  *                fpStream: pointer to output file stream
  240.  *                nMode    : Channel Mode: 0=STEREO 1=JS 2=DS 3=MONO
  241.  ****************************************************************************
  242. */
  243. int InitVbrTag(lame_global_flags *gfp)
  244. {
  245.     int nMode,SampIndex;
  246.     lame_internal_flags *gfc = gfp->internal_flags;
  247.     u_char pbtStreamBuffer[216];
  248.     nMode = gfp->mode;
  249.     SampIndex = gfc->samplerate_index;
  250.  
  251.  
  252.     /* Clear Frame position array variables */
  253.     gfp->pVbrFrames=NULL;
  254.     gfp->nVbrNumFrames=0;
  255.     gfp->nVbrFrameBufferSize=0;
  256.  
  257.  
  258.     /* Clear stream buffer */
  259.     memset(pbtStreamBuffer,0x00,sizeof(pbtStreamBuffer));
  260.  
  261.  
  262.  
  263.     /* Reserve the proper amount of bytes */
  264.     if (nMode==3)
  265.     {
  266.         gfp->nZeroStreamSize=SizeOfEmptyFrame[gfp->version][1]+4;
  267.     }
  268.     else
  269.     {
  270.         gfp->nZeroStreamSize=SizeOfEmptyFrame[gfp->version][0]+4;
  271.     }
  272.  
  273.     /*
  274.     // Xing VBR pretends to be a 48kbs layer III frame.  (at 44.1kHz).
  275.         // (at 48kHz they use 56kbs since 48kbs frame not big enough for
  276.         // table of contents)
  277.     // let's always embed Xing header inside a 64kbs layer III frame.
  278.     // this gives us enough room for a LAME version string too.
  279.     // size determined by sampling frequency (MPEG1)
  280.     // 32kHz:    216 bytes@48kbs    288bytes@ 64kbs
  281.     // 44.1kHz:  156 bytes          208bytes@64kbs     (+1 if padding = 1)
  282.     // 48kHz:    144 bytes          192
  283.     //
  284.     // MPEG 2 values are the since the framesize and samplerate
  285.         // are each reduced by a factor of 2.
  286.     */
  287.     {
  288.     int tot;
  289.     static const int framesize[3]={208,192,288};  /* 64kbs MPEG1 or MPEG2  framesize */
  290.     /* static int framesize[3]={156,144,216}; */ /* 48kbs framesize */
  291.  
  292.     if (SampIndex>2) {
  293.       ERRORF("illegal sampling frequency index\n");
  294.       LAME_ERROR_EXIT();
  295.     }
  296.     gfp->TotalFrameSize= framesize[SampIndex];
  297.     tot = (gfp->nZeroStreamSize+VBRHEADERSIZE);
  298.     tot += 20;  /* extra 20 bytes for LAME & version string */
  299.  
  300.     if (gfp->TotalFrameSize < tot ) {
  301.       ERRORF("Xing VBR header problem...use -t\n");
  302.       LAME_ERROR_EXIT();
  303.     }
  304.     }
  305.  
  306.     add_dummy_vbrframe(gfp,8*gfp->TotalFrameSize);
  307.  
  308.     /* Success */
  309.     return 0;
  310. }
  311.  
  312.  
  313.  
  314. /****************************************************************************
  315.  * PutVbrTag: Write final VBR tag to the file
  316.  * Paramters:
  317.  *                lpszFileName: filename of MP3 bit stream
  318.  *                nVbrScale    : encoder quality indicator (0..100)
  319.  ****************************************************************************
  320. */
  321. int PutVbrTag(lame_global_flags *gfp,char* lpszFileName,int nVbrScale)
  322. {
  323.     int            i;
  324.     long lFileSize;
  325.     int nStreamIndex;
  326.     char abyte;
  327.     u_char        btToc[NUMTOCENTRIES];
  328.     FILE *fpStream;
  329.         u_char pbtStreamBuffer[216];
  330.     char str1[80];
  331.  
  332.     if (gfp->nVbrNumFrames==0 || gfp->pVbrFrames==NULL)
  333.         return -1;
  334.  
  335.     /* Open the bitstream again */
  336.     fpStream=fopen(lpszFileName,"rb+");
  337.  
  338.     /* Assert stream is valid */
  339.     if (fpStream==NULL)
  340.         return -1;
  341.  
  342.     /* Clear stream buffer */
  343.     memset(pbtStreamBuffer,0x00,sizeof(pbtStreamBuffer));
  344.  
  345.     /* Seek to end of file*/
  346.     fseek(fpStream,0,SEEK_END);
  347.  
  348.     /* Get file size */
  349.     lFileSize=ftell(fpStream);
  350.  
  351.     /* Abort if file has zero length. Yes, it can happen :) */
  352.     if (lFileSize==0)
  353.         return -1;
  354.  
  355.     /* Seek to first real frame */
  356.     fseek(fpStream,(long)gfp->TotalFrameSize,SEEK_SET);
  357.  
  358.     /* Read the header (first valid frame) */
  359.     fread(pbtStreamBuffer,4,1,fpStream);
  360.  
  361.     /* the default VBR header.  48kbs layer III, no padding, no crc */
  362.     /* but sampling freq, mode andy copyright/copy protection taken */
  363.     /* from first valid frame */
  364.     pbtStreamBuffer[0]=(u_char) 0xff;
  365.     abyte = (pbtStreamBuffer[1] & (char) 0xf0);
  366.     if (gfp->version==1) {
  367.       pbtStreamBuffer[1]=abyte | (char) 0x0b;
  368.       abyte = pbtStreamBuffer[2] & (char) 0x0d;   /* AF keep also private bit */
  369.       pbtStreamBuffer[2]=(char) 0x50 | abyte;     /* 64kbs MPEG1 frame */
  370.     }else{
  371.       pbtStreamBuffer[1]=abyte | (char) 0x03;
  372.       abyte = pbtStreamBuffer[2] & (char) 0x0d;   /* AF keep also private bit */
  373.       pbtStreamBuffer[2]=(char) 0x80 | abyte;     /* 64kbs MPEG2 frame */
  374.     }
  375.  
  376.  
  377.     /*Seek to the beginning of the stream */
  378.     fseek(fpStream,0,SEEK_SET);
  379.  
  380.     /* Clear all TOC entries */
  381.     memset(btToc,0,sizeof(btToc));
  382.  
  383.         for (i=1;i<NUMTOCENTRIES;i++) /* Don't touch zero point... */
  384.         {
  385.                 /* Calculate frame from given percentage */
  386.                 int frameNum=(int)(floor(0.01*i*gfp->nVbrNumFrames));
  387.  
  388.                 /*  Calculate relative file postion, normalized to 0..256!(?) */
  389.                 float fRelStreamPos=(float)256.0*(float)gfp->pVbrFrames[frameNum]/(float)lFileSize;
  390.  
  391.                 /* Just to be safe */
  392.                 if (fRelStreamPos>255) fRelStreamPos=255;
  393.  
  394.                 /* Assign toc entry value */
  395.                 btToc[i]=(u_char) fRelStreamPos;
  396.         }
  397.  
  398.  
  399.  
  400.     /* Start writing the tag after the zero frame */
  401.     nStreamIndex=gfp->nZeroStreamSize;
  402.  
  403.     /* Put Vbr tag */
  404.     pbtStreamBuffer[nStreamIndex++]=VBRTag[0];
  405.     pbtStreamBuffer[nStreamIndex++]=VBRTag[1];
  406.     pbtStreamBuffer[nStreamIndex++]=VBRTag[2];
  407.     pbtStreamBuffer[nStreamIndex++]=VBRTag[3];
  408.  
  409.     /* Put header flags */
  410.     CreateI4(&pbtStreamBuffer[nStreamIndex],FRAMES_FLAG+BYTES_FLAG+TOC_FLAG+VBR_SCALE_FLAG);
  411.     nStreamIndex+=4;
  412.  
  413.     /* Put Total Number of frames */
  414.     CreateI4(&pbtStreamBuffer[nStreamIndex],gfp->nVbrNumFrames);
  415.     nStreamIndex+=4;
  416.  
  417.     /* Put Total file size */
  418.     CreateI4(&pbtStreamBuffer[nStreamIndex],(int)lFileSize);
  419.     nStreamIndex+=4;
  420.  
  421.     /* Put TOC */
  422.     memcpy(&pbtStreamBuffer[nStreamIndex],btToc,sizeof(btToc));
  423.     nStreamIndex+=sizeof(btToc);
  424.  
  425.     /* Put VBR SCALE */
  426.     CreateI4(&pbtStreamBuffer[nStreamIndex],nVbrScale);
  427.     nStreamIndex+=4;
  428.  
  429.     /* Put LAME id */
  430.     sprintf(str1,"LAME%s",get_lame_version());
  431.     strncpy((char *)&pbtStreamBuffer[nStreamIndex],str1,(size_t) 20);
  432.     nStreamIndex+=20;
  433.  
  434.  
  435. #ifdef DEBUG_VBRTAG
  436. {
  437.     VBRTAGDATA TestHeader;
  438.     GetVbrTag(&TestHeader,pbtStreamBuffer);
  439. }
  440. #endif
  441.  
  442.         /* Put it all to disk again */
  443.     if (fwrite(pbtStreamBuffer,(unsigned int)gfp->TotalFrameSize,1,fpStream)!=1)
  444.     {
  445.         return -1;
  446.     }
  447.     fclose(fpStream);
  448.  
  449.     /* Save to delete the frame buffer */
  450.     free(gfp->pVbrFrames);
  451.     gfp->pVbrFrames=NULL;
  452.  
  453.     return 0;       /* success */
  454. }
  455.  
  456. /*-------------------------------------------------------------*/
  457. int SeekPoint(unsigned char TOC[NUMTOCENTRIES], int file_bytes, float percent)
  458. {
  459. /* interpolate in TOC to get file seek point in bytes */
  460. int a, seekpoint;
  461. float fa, fb, fx;
  462.  
  463.  
  464. if( percent < (float)0.0 )   percent = (float)0.0;
  465. if( percent > (float)100.0 ) percent = (float)100.0;
  466.  
  467. a = (int)percent;
  468. if( a > 99 ) a = 99;
  469. fa = TOC[a];
  470. if( a < 99 ) {
  471.     fb = TOC[a+1];
  472. }
  473. else {
  474.     fb = (float)256.0;
  475. }
  476.  
  477.  
  478. fx = fa + (fb-fa)*(percent-a);
  479.  
  480. seekpoint = (int)(((float)(1.0/256.0))*fx*file_bytes);
  481.  
  482.  
  483. return seekpoint;
  484. }
  485. /*-------------------------------------------------------------*/
  486.